/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once


#include "../Vec3.h"


/*
inline bool IntersectLineSegmentPlane(const Vec3& start, const Vec3& end, const Plane& plane, Vec3& out)
{
	Vec3 u(end - start);

	float dist = -Dot(plane, start) / Dot(plane, u);

	if (dist > 0.0f && dist < 1.0f)
	{
		out = (start + u * dist);
		return true;
	}
	else
		return false;
}
*/

// Moller and Trumbore's method IntersectRayTriTwoSided
inline bool f_三角形射线双面相交(const Vec3& p, const Vec3& dir, const Vec3& a, const Vec3& b, const Vec3& c, float& t, float& u, float& v, float& w, float& sign)//Vec3* normal)
{
	Vec3 ab = b - a;
	Vec3 ac = c - a;
	Vec3 n = f_Cross(ab, ac);

	float d = f_Dot(-dir, n);
	float ood = 1.0f / d; // No need to check for division by zero here as infinity aritmetic will save us...
	Vec3 ap = p - a;

	t = f_Dot(ap, n) * ood;
	if (t < 0.0f)
		return false;

	Vec3 e = f_Cross(-dir, ap);
	v = f_Dot(ac, e) * ood;
	if (v < 0.0f || v > 1.0f) // ...here...
		return false;
	w = -f_Dot(ab, e) * ood;
	if (w < 0.0f || v + w > 1.0f) // ...and here
		return false;

	u = 1.0f - v - w;
	//if (normal)
		//*normal = n;
	sign = d;

	return true;
}






//IntersectRayAABB
CUDA_CALLABLE inline bool f_射线相交AABB(const Vec3& start, const Vec3& dir, const Vec3& min, const Vec3& max, float& t, Vec3* normal)
{
	//! calculate candidate plane on each axis
	float tx = -1.0f, ty = -1.0f, tz = -1.0f;
	bool inside = true;

	//! use unrolled loops

	//! x
	if (start.x < min.x) {
		if (dir.x != 0.0f)
			tx = (min.x - start.x) / dir.x;
		inside = false;
	} else if (start.x > max.x) {
		if (dir.x != 0.0f)
			tx = (max.x - start.x) / dir.x;
		inside = false;
	}

	//! y
	if (start.y < min.y) {
		if (dir.y != 0.0f)
			ty = (min.y - start.y) / dir.y;
		inside = false;
	} else if (start.y > max.y) {
		if (dir.y != 0.0f)
			ty = (max.y - start.y) / dir.y;
		inside = false;
	}

	//! z
	if (start.z < min.z) {
		if (dir.z != 0.0f)
			tz = (min.z - start.z) / dir.z;
		inside = false;
	} else if (start.z > max.z) {
		if (dir.z != 0.0f)
			tz = (max.z - start.z) / dir.z;
		inside = false;
	}

	//! if point inside all planes
	if (inside) {
		t = 0.0f;
		return true;
	}

	//! we now have t values for each of possible intersection planes
	//! find the maximum to get the intersection point
	float tmax = tx;
	int taxis = 0;

	if (ty > tmax) {
		tmax = ty;
		taxis = 1;
	}
	if (tz > tmax) {
		tmax = tz;
		taxis = 2;
	}

	if (tmax < 0.0f)
		return false;

	//! check that the intersection point lies on the plane we picked
	//! we don't test the axis of closest intersection for precision reasons

	//! no eps for now
	float eps = 0.0f;

	Vec3 hit = start + dir * tmax;

	if ((hit.x < min.x - eps || hit.x > max.x + eps) && taxis != 0)
		return false;
	if ((hit.y < min.y - eps || hit.y > max.y + eps) && taxis != 1)
		return false;
	if ((hit.z < min.z - eps || hit.z > max.z + eps) && taxis != 2)
		return false;

	//! output results
	t = tmax;

	return true;
}




